home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / bit / src / mdbg.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  9KB  |  384 lines

  1. /*
  2.  * $Id: mdbg.c,v 0.91 1994/02/20 02:17:36 zhao Exp $
  3.  *
  4.  *. This file is part of BIT shareware package. After the two weeks of
  5.  *  free evaluation period, you are encouraged (required) to register
  6.  *  your copy for a small registration fee, which is $35 for personal use
  7.  *  and $50 for commercial, government and institutional use.
  8.  *
  9.  *  Copyright(c) 1993, 1994 by T.C. Zhao.
  10.  *  All rights reserved.
  11.  *
  12.  *  Permission to use, copy, and distribute this software in its entirety
  13.  *  for non-commercial purposes is hereby granted, provided that the
  14.  *  above shareware and copyright notices and this permission notice
  15.  *  appear in all copies and their documentation.
  16.  *
  17.  *  This software may be modified for your own use, but modified versions
  18.  *  may not be distributed without prior consent of the author.
  19.  *
  20.  *  This software is provided "as is" without expressed or implied
  21.  *  warranty of any kind.
  22.  *
  23.  *.
  24.  *
  25.  * Wrapper for malloc and its cousins.
  26.  * All routines work by calling true malloc with some extra space
  27.  * for signatures, where is is called and other info. When request
  28.  * to free, realloc etc is called, these info is examined to make
  29.  * sure the memory handed over is ok. In addition, memory usage
  30.  * statistics can be obtained anywhere by calling mem_stat which
  31.  * will print out all malloced memory that are not yet freed and
  32.  * functions and line no. where malloc is called.
  33.  *
  34.  * WARNING:  Neither efficient nor portable. It assumes 4 bytes
  35.  * alignment.
  36.  *
  37.  */
  38.  
  39. #ifdef M_DBG
  40.  
  41. #if !defined(lint) && defined(F_ID)
  42. char *id_dbgm = "$Id: mdbg.c,v 0.91 1994/02/20 02:17:36 zhao Exp $";
  43. #endif
  44.  
  45. #define M_DBG_OWNER        /* dmalloc.h notices this and refrain from
  46.                  * replacing malloc with dbg_malloc */
  47.  
  48. #include <stdio.h>
  49. #include <string.h>
  50. #include "ulib.h"
  51. #include "dmalloc.h"
  52.  
  53. typedef long STYPE;        /* must be at least 4bytes long   */
  54.  
  55. #define MAX_FL     15
  56. #define MAX_REC    500        /* max malloc etc record to keep  */
  57. #define OK_MEM     0xcfdcfaef    /* good memory head signature     */
  58. #define ED_MEM     0xdfefafdf    /* good memory end signature      */
  59. #define FR_MEM     0xeffbffcf    /* freed block                    */
  60. #define TOTAL_OFF  3*sizeof(STYPE)    /* user memory starts 3 ints off */
  61.  
  62. static struct
  63.   {
  64.       void *ptr;        /* pointer returned by malloc etc */
  65.       char where[MAX_FL + 1];    /* functions that called malloc  */
  66.       int line;            /* line number in function       */
  67.   }
  68. m_rec[MAX_REC];
  69.  
  70. /*
  71.  * True free from malloc.h or stdlib.h if no debug is used, Tfree will be a
  72.  * macros that degenerates into free
  73.  */
  74. void
  75. Tfree(void *p)
  76. {
  77.     free(p);
  78. }
  79.  
  80. /* how to handle error messages. */
  81. static int mem_warn = 1;
  82. void
  83. set_mem_warn(int y)
  84. {
  85.     mem_warn = y;
  86. }
  87.  
  88. /*
  89.  * Even if STYPE is 4bytes long, can't simply do a *p= s because *p
  90.  * might not be properly aligned. Remember, we are dealing with memory
  91.  * handed over by users.
  92.  */
  93. static void
  94. set_4bytes(void *p, STYPE s)
  95. {
  96.     register unsigned char *pp = p;
  97.  
  98.     *pp++ = (s & 0xff);
  99.     *pp++ = ((s >> 8) & 0xff);
  100.     *pp++ = ((s >> 16) & 0xff);
  101.     *pp = ((s >> 24) & 0xff);
  102. }
  103.  
  104. /* peek 4 bytes */
  105. static void
  106. get_4bytes(void *p, STYPE * s)
  107. {
  108.     register unsigned char *pp = p;
  109.     register STYPE a, b, c, d;
  110.  
  111.     a = *pp++;
  112.     b = *pp++;
  113.     c = *pp++;
  114.     d = *pp;
  115.     *s = (STYPE) a | (b << 8) | (c << 16) | (d << 24);
  116. }
  117.  
  118. /* error output routine obeying mem_warn settings */
  119. static void
  120. mprintf(const char *fi, int line, const char *func, const char *s2)
  121. {
  122.     if (mem_warn <= 0)
  123.       {                /* text only */
  124.       M_msg(ML_ERR, fi, line) (func, s2);
  125.       }
  126.     else
  127.       {
  128.       GM_msg(0, fi, line) (func, s2);
  129.       }
  130. }
  131.  
  132. static int
  133. find_index(const char *f, int line, const char *fun)
  134. {
  135.     register int i;
  136.     static int warned;
  137.  
  138.     for (i = 0; i < MAX_REC; i++)
  139.     if (!m_rec[i].ptr)
  140.         return i;
  141.     if (warned < 2)
  142.       {
  143.       mprintf(f, line, fun, "m_dbg record out of bounds");
  144.       warned++;
  145.       }
  146.     return -1;
  147. }
  148.  
  149. /* insert signature, size and other info into malloc'ed mem */
  150. static void
  151. set_marker(void *p, STYPE sig, STYPE ind, STYPE size, STYPE esig)
  152. {
  153.     register unsigned char *pp = p;
  154.  
  155.     set_4bytes(pp, sig);
  156.     pp += sizeof(STYPE);
  157.     set_4bytes(pp, ind);
  158.     pp += sizeof(STYPE);
  159.     set_4bytes(pp, size - TOTAL_OFF);
  160.     pp += sizeof(STYPE);
  161.     pp = (unsigned char *) p + size;
  162.     set_4bytes(pp, esig);
  163. }
  164.  
  165. /* get signature etc from the pointer in request to free, realloc etc*/
  166. static void
  167. get_marker(void *p, STYPE * sig, STYPE * ind,
  168.        STYPE * size, STYPE * esig)
  169. {
  170.     register unsigned char *pp = p;
  171.  
  172.     get_4bytes(pp, sig);
  173.     if (*sig != OK_MEM)
  174.     return;
  175.     pp += sizeof(STYPE);
  176.     get_4bytes(pp, ind);
  177.     if (*ind < 0 || *ind > MAX_REC - 1)
  178.     return;
  179.     pp += sizeof(STYPE);
  180.     get_4bytes(pp, size);
  181.     if (*size < 0)
  182.     return;
  183.     pp += sizeof(STYPE);
  184.     pp = (unsigned char *) p + *size + TOTAL_OFF;
  185.     get_4bytes(pp, esig);
  186.     if (*esig != ED_MEM)
  187.     return;
  188. }
  189.  
  190. static int totalgets, totalfree;
  191. static int
  192. check_sig(void *p, const char *f, int line, const char *func)
  193. {
  194.     STYPE sig = -1, sz = -1, ind = -1, esig = -1;
  195.  
  196.     get_marker(p, &sig, &ind, &sz, &esig);
  197.     if (sig == FR_MEM)
  198.       {
  199.       mprintf(f, line, func, "referencing a freed block");
  200.       return -1;
  201.       }
  202.     if (sig != OK_MEM)
  203.       {
  204.       mprintf(f, line, func, "mem not malloced or is corrupted");
  205.       return -1;
  206.       }
  207.     if (ind < 0 || ind > MAX_REC - 1)
  208.       {
  209.       mprintf(f, line, func, "corrupted mem(index)");
  210.       return -1;
  211.       }
  212.     if (esig != ED_MEM)
  213.       {
  214.       mprintf(f, line, func, "malloc mem overrun at end");
  215.       return -1;
  216.       }
  217.     return ind;
  218. }
  219.  
  220. /*
  221.  * the func is where the dyn. alloc started, possibly appened with other
  222.  * routines that called malloc (cf. strdup)
  223.  */
  224. void *
  225. dbg_malloc(size_t size, const char *func, int line)
  226. {
  227.     register void *p;
  228.     register STYPE ind;
  229.  
  230.     size += TOTAL_OFF;
  231.     if (!(p = malloc(size + sizeof(STYPE))))
  232.       {
  233.       mprintf(func, line, "d_malloc", "malloc failed");
  234.       return 0;
  235.       }
  236.     totalgets++;
  237.     if ((ind = find_index(func, line, "d_malloc")) < 0)
  238.     return p;
  239.     set_marker(p, OK_MEM, ind, size, ED_MEM);
  240.     m_rec[ind].ptr = p;
  241.     m_rec[ind].where[MAX_FL] = '\0';
  242.     strncpy(m_rec[ind].where, func, MAX_FL);
  243.     m_rec[ind].line = line;
  244.     p = (char *) p + TOTAL_OFF;
  245.     return p;
  246. }
  247.  
  248. void *
  249. dbg_calloc(size_t nelem, size_t esize, const char *f, int line)
  250. {
  251.     register void *p;
  252.     register size_t size = (nelem * esize);
  253.  
  254.     if (!(p = dbg_malloc(size, f, line)))
  255.     return 0;
  256.     memset(p, 0, size);
  257.     return p;
  258. }
  259.  
  260. void *
  261. dbg_realloc(void *p, size_t nsize, const char *f, int line)
  262. {
  263.     register STYPE ind;
  264.     register char *pc;
  265.  
  266.     if (!p)
  267.       {
  268.       mprintf(f, line, "d_realloc", "NullPtr passed to realloc");
  269.       return 0;
  270.       }
  271.     pc = (char *) p - TOTAL_OFF;
  272.     if ((ind = check_sig(pc, f, line, "d_realloc")) < 0)
  273.     return 0;
  274.     nsize += TOTAL_OFF;
  275.     if (!(pc = realloc(pc, nsize + sizeof(STYPE))))
  276.       {
  277.       mprintf(f, line, "d_realloc", "realloc failed");
  278.       return 0;
  279.       }
  280.     set_marker(pc, OK_MEM, ind, nsize, ED_MEM);
  281.     m_rec[ind].ptr = pc;
  282.     pc += TOTAL_OFF;
  283.     return pc;
  284. }
  285.  
  286. void
  287. dbg_free(void *p, const char *f, int line)
  288. {
  289.     char *a;
  290.     STYPE ind;
  291.  
  292.     if (!p)
  293.       {
  294.       mprintf(f, line, "d_free", "NullPtr passed to free");
  295.       return;
  296.       }
  297.     a = (char *) p - TOTAL_OFF;
  298.     if ((ind = check_sig(a, f, line, "d_free")) < 0)
  299.     return;
  300.     set_4bytes(a, FR_MEM);
  301.     totalfree++;
  302.     m_rec[ind].ptr = 0;
  303.     free(a);
  304. }
  305.  
  306. /* replace strdup from string.h */
  307. char *
  308. dbg_strdup(const char *s, const char *func, int line)
  309. {
  310.     static char local[101];
  311.     char *p;
  312.  
  313.     local[0] = '\0';
  314.     if (func)
  315.       {
  316.       strncat(local, func, 100);
  317.       local[100] = '\0';
  318.       }
  319.     strncat(local, "_strdup", 100);
  320.  
  321.     p = dbg_malloc(strlen(s) + 1, local, line);
  322.     return p ? strcpy(p, s) : p;
  323. }
  324.  
  325. /* print out memoery usage statistics */
  326. void
  327. mem_stat(void)
  328. {
  329.     int i, diff, line;
  330.     STYPE sig, size, ind, esig;
  331.     void *p;
  332.     char *func;
  333.     double total = 0;
  334.  
  335.     /*
  336.      * if mem is corrupt, we do not want to activate tc_gmsg, there could be
  337.      * zillions of messages!
  338.      */
  339.     set_mem_warn(-1);
  340.     fprintf(stderr, "\nThere are %d malloc and %d free, unfreed are\n",
  341.         totalgets, totalfree);
  342.     diff = totalgets - totalfree;
  343.     for (i = 0; i < MAX_REC; i++)
  344.       {
  345.       if ((p = m_rec[i].ptr))
  346.         {
  347.         func = m_rec[i].where;
  348.         line = m_rec[i].line;
  349.         (void) check_sig(p, "mem_stat record no.", i, "memstat");
  350.         get_marker(p, &sig, &ind, &size, &esig);
  351.         total += size;
  352.         if (ind < 0 || ind > MAX_REC - 1)
  353.             mprintf("memstat:", i, "", "bad mem block");
  354.         else
  355.             fprintf(stderr,
  356.                 "%20s line %-d:\t size %-9ld index(%d)=%ld\n",
  357.                 func, line, size, i, ind);
  358.         diff--;
  359.         }
  360.       }
  361.     if (diff)
  362.     fprintf(stderr, "things are not quite right in mem_stat\n");
  363.     fprintf(stderr, " Total unfreeed: %.0f bytes\n", total);
  364. }
  365.  
  366. #else /* !M_DBG   no_op for mem_warn */
  367.  
  368. #include "dmalloc.h"        /* still wants to have prototypes */
  369.  
  370. /* ARGSUSED */
  371. void
  372. set_mem_warn(int y)
  373. {
  374.     return;
  375. }
  376.  
  377. void
  378. mem_stat(void)
  379. {
  380.     return;
  381. }
  382.  
  383. #endif
  384.